POI2008 Triangles

POI2008 Triangles

题目大意:

平面上有n个点,求出所有以这n个点为顶点的三角形的面积和。

($n \le 3000$)

题解:

首先可以明确,我们用向量的叉积来获得三角形的面积。

如果直接枚举三个点,分别算面积的话,复杂度为$O(n^3)$显然会TLE。

但由于向量叉积的符号有正有负,我们没法利用前缀和之类的技巧来优化。

于是,可以这样:

先把点从左到右排序一下,每次取最左边的一个点。

把该点与该点右边的点连出的向量全部记录下来。

那么接下来就是算这些向量两两的叉积。

为了避免正负号的干扰,我们首先将它们极角排序。

之后即可利用前缀和来优化了。

综上,总的时间复杂度为$O(n^2logn)$ 。

Code:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
#include<stdio.h>
#include<string.h>
#include<iostream>
#include<algorithm>
using namespace std;
typedef long long ll;
void Rd(ll&res){
res=0;char c;
while(c=getchar(),c<48);
do res=res*10+(c&15);
while(c=getchar(),c>47);
}
const int N=3005;
struct Point{
ll x,y;
bool operator <(const Point&a)const{
if(x!=a.x)return x<a.x;
return y<a.y;
}
}pos[N];
typedef Point Vector;
Vector vec[N],sum;
ll operator* (const Vector&a,const Vector&b){
return a.x*b.y-a.y*b.x;
}
Vector operator+ (const Point&a,const Point&b){
return (Vector){a.x+b.x,a.y+b.y};
}
Vector operator- (const Point&a,const Point&b){
return (Vector){a.x-b.x,a.y-b.y};
}
bool cmp(const Vector&a,const Vector&b){
return a*b>0;
}
ll n,len;
int main(){
Rd(n);
for(int i=1;i<=n;i++)
Rd(pos[i].x),Rd(pos[i].y);
sort(pos+1,pos+1+n);
ll ans=0;
for(int i=1;i<=n;i++){//原点
len=sum.x=sum.y=0;
for(int j=i+1;j<=n;j++){
vec[++len]=pos[j]-pos[i];
sum=sum+vec[len];
}
sort(vec+1,vec+1+len,cmp);//极角排序
for(int j=1;j<=len;j++){
sum=sum-vec[j];
ans+=vec[j]*sum;
}
}
if(ans&1)printf("%lld.5\n",ans/2);
else printf("%lld.0\n",ans/2);
return 0;
}
分享到 评论